
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Server-Side Rendering - vue.js</title>
        <meta charset="utf-8">
        <meta name="description" content="Vue.js - Intuitive, Fast and Composable MVVM for building interactive interfaces.">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        <link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600|Roboto Mono' rel='stylesheet' type='text/css'>
        <link href='//fonts.googleapis.com/css?family=Dosis:300,500&text=Vue.js' rel='stylesheet' type='text/css'>
        <link href="//cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" rel='stylesheet' type='text/css'>
        <link rel="icon" href="/images/logo.png" type="image/x-icon">
        <script>
            window.PAGE_TYPE = "guide"
        </script>
        <link rel="stylesheet" href="/css/page.css">
        <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-46852172-1', 'vuejs.org');
  ga('send', 'pageview');
</script>
        <script src="/js/vue.js"></script>
    </head>
    <body>
        <div id="mobile-bar">
            <a class="menu-button"></a>
            <a class="logo" href="/"></a>
        </div>
        
            <div id="header">
  <a id="logo" href="/">
    <img src="/images/logo.png">
    <span>Vue.js <sup>2.0 RC</sup></span>
  </a>
  <span style="
    position: absolute;
    top: 100%;
    left: 60px;
    padding: 0 10px;
    background: #ef9f00;
    border-radius: 3px;
    margin-top: -15px;
    line-height: 30px;
    color: white;
    font-weight: bold;
    letter-spacing: 1px;
    box-shadow: 0 1px 2px rgba(0,0,0,.3);
  ">
    WORK IN PROGRESS
  </span>
  <ul id="nav">
    <li>
  <form id="search-form">
    <input type="text" id="search-query-nav" class="search-query st-default-search-input">
  </form>
</li>
<li><a href="/guide/" class="nav-link current">Guide</a></li>
<li><a href="/api/" class="nav-link">API</a></li>
<li><a href="/examples/" class="nav-link">Examples</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li class="nav-dropdown-container">
  <a class="nav-link">Community</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="https://github.com/vuejs/vue" class="nav-link" target="_blank">GitHub</a></li>
    <li><a href="http://forum.vuejs.org" class="nav-link" target="_blank">Forum</a></li>
    <li><a href="https://gitter.im/vuejs/vue" class="nav-link" target="_blank">Chat</a></li>
    <li><a href="https://twitter.com/vuejs" class="nav-link" target="_blank">Twitter</a></li>
  </ul>
</li>


  </ul>
</div>

            <div id="main">
                
                    
    <div class="sidebar">
    <ul class="main-menu">
        <li>
  <form id="search-form">
    <input type="text" id="search-query-sidebar" class="search-query st-default-search-input">
  </form>
</li>
<li><a href="/guide/" class="nav-link current">Guide</a></li>
<li><a href="/api/" class="nav-link">API</a></li>
<li><a href="/examples/" class="nav-link">Examples</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li class="nav-dropdown-container">
  <a class="nav-link">Community</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="https://github.com/vuejs/vue" class="nav-link" target="_blank">GitHub</a></li>
    <li><a href="http://forum.vuejs.org" class="nav-link" target="_blank">Forum</a></li>
    <li><a href="https://gitter.im/vuejs/vue" class="nav-link" target="_blank">Chat</a></li>
    <li><a href="https://twitter.com/vuejs" class="nav-link" target="_blank">Twitter</a></li>
  </ul>
</li>


    </ul>
    <div class="list">
        <div id="donate" style="margin-bottom: 20px">
            <span class="wrapper" style="width: 110px">
              <img src="/images/patreon.png">
              <a href="/support-vuejs">Support Vue.js</a>
            </span>
        </div>
        <h2>
            Guide
            <select class="version-select">
                <option value="rc" selected>2.0</option>
                <!-- !!TODO: Update value to subdomain when 2.0 is released -->
                <option value="">1.0</option>
                <option>0.12</option>
                <option>0.11</option>
            </select>
        </h2>
        <ul class="menu-root">
            
                
                
                  <li><h3>Essentials</h3></li>
                
                
                
                <li>
                    <a href="/guide/installation.html" class="sidebar-link">Installation</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/index.html" class="sidebar-link">Introduction</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/instance.html" class="sidebar-link">The Vue Instance</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/syntax.html" class="sidebar-link">Template Syntax</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/computed.html" class="sidebar-link">Computed Properties and Watchers</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/class-and-style.html" class="sidebar-link">Class and Style Bindings</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/conditional.html" class="sidebar-link">Conditional Rendering</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/list.html" class="sidebar-link">List Rendering</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/events.html" class="sidebar-link">Event Handling</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/forms.html" class="sidebar-link">Form Input Bindings</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/components.html" class="sidebar-link">Components</a>
                </li>
            
                
                
                
                  <li><h3>Advanced</h3></li>
                
                
                <li>
                    <a href="/guide/transitions.html" class="sidebar-link">Transitions: Entering, Leaving, and Lists</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/transitioning-state.html" class="sidebar-link">Transitioning State</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/render-function.html" class="sidebar-link">Render Functions</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/reactivity.html" class="sidebar-link">Reactivity in Depth</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/custom-directive.html" class="sidebar-link">Custom Directives</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/mixins.html" class="sidebar-link">Mixins</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/plugins.html" class="sidebar-link">Plugins</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/single-file-components.html" class="sidebar-link">Single File Components</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/routing.html" class="sidebar-link">Routing</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/state-management.html" class="sidebar-link">State Management</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/unit-testing.html" class="sidebar-link">Unit Testing</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/ssr.html" class="sidebar-link current">Server-Side Rendering</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/migration.html" class="sidebar-link">Migration from 1.x</a>
                </li>
            
                
                
                
                
                  <li><h3>Meta</h3></li>
                
                <li>
                    <a href="/guide/comparison.html" class="sidebar-link">Comparison with Other Frameworks</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/join.html" class="sidebar-link">Join the Vue.js Community!</a>
                </li>
            
        </ul>
    </div>
</div>


<div class="content guide with-sidebar ssr-guide">
    <div id="ad">
  <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=vuejs" id="_carbonads_js"></script>
</div>

    <h1>Server-Side Rendering</h1>
    <h2 id="Do-You-Need-SSR"><a href="#Do-You-Need-SSR" class="headerlink" title="Do You Need SSR?"></a>Do You Need SSR?</h2><p>Before diving into SSR, let’s explore what it actually does for you and when you might need it.</p>
<h3 id="SEO"><a href="#SEO" class="headerlink" title="SEO"></a>SEO</h3><p>Google and Bing can index synchronous JavaScript applications just fine. <em>Synchronous</em> being the key word there. If your app starts with a loading spinner, then fetches content via Ajax, the crawler will not wait for you to finish.</p>
<p>This means if you have content fetched asynchronously on pages where SEO is important, SSR might be necessary.</p>
<h3 id="Clients-with-a-Slow-Internet"><a href="#Clients-with-a-Slow-Internet" class="headerlink" title="Clients with a Slow Internet"></a>Clients with a Slow Internet</h3><p>Users might come to your site from a remote area with slow Internet - or just with a bad cell connection. In these cases, you’ll want to minimize the number and size of requests necessary for users to see basic content.</p>
<p>You can use <a href="https://webpack.github.io/docs/code-splitting.html" target="_blank" rel="external">Webpack’s code splitting</a> to avoid forcing users to download your entire application to view a single page, but it still won’t be as performant as downloading a single, pre-rendered HTML file.</p>
<h3 id="Clients-with-an-Old-or-Simply-No-JavaScript-Engine"><a href="#Clients-with-an-Old-or-Simply-No-JavaScript-Engine" class="headerlink" title="Clients with an Old (or Simply No) JavaScript Engine"></a>Clients with an Old (or Simply No) JavaScript Engine</h3><p>For some demographics or areas of the world, using a computer from 1998 to access the Internet might be the only option. While Vue only works with IE9+, you may still want to deliver basic content to those on older browsers - or to hipster hackers using <a href="http://lynx.browser.org/" target="_blank" rel="external">Lynx</a> in the terminal.</p>
<h3 id="SSR-vs-Prerendering"><a href="#SSR-vs-Prerendering" class="headerlink" title="SSR vs Prerendering"></a>SSR vs Prerendering</h3><p>If you’re only investigating SSR to improve the SEO of a handful of marketing pages (e.g. <code>/</code>, <code>/about</code>, <code>/contact</code>, etc), then you probably want <strong>prerendering</strong> instead. Rather than using a web server to compile HTML on-the-fly, prerendering simply generates static HTML files for specific routes at build time. The advantage is setting up prerendering is much simpler and allows you to keep your frontend as a fully static site.</p>
<p>If you’re using Webpack, you can easily add prerendering with the <a href="https://github.com/chrisvfritz/prerender-spa-plugin" target="_blank" rel="external">prerender-spa-plugin</a>. It’s been extensively tested with Vue apps - and in fact, the creator is a member of the Vue core team.</p>
<h2 id="Hello-World"><a href="#Hello-World" class="headerlink" title="Hello World"></a>Hello World</h2><p>If you’ve gotten this far, you’re ready to see SSR in action. It sounds complex, but a simple node script demoing the feature requires only 3 steps:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="comment">// Step 1: Create a Vue instance</span></div><div class="line"><span class="keyword">var</span> Vue = <span class="built_in">require</span>(<span class="string">'vue'</span>)</div><div class="line"><span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</div><div class="line">  render: <span class="function"><span class="keyword">function</span> (<span class="params">h</span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> h(<span class="string">'p'</span>, <span class="string">'hello world'</span>)</div><div class="line">  &#125;</div><div class="line">&#125;)</div><div class="line"></div><div class="line"><span class="comment">// Step 2: Create a renderer</span></div><div class="line"><span class="keyword">var</span> renderer = <span class="built_in">require</span>(<span class="string">'vue-server-renderer'</span>).createRenderer()</div><div class="line"></div><div class="line"><span class="comment">// Step 3: Render the Vue instance to HTML</span></div><div class="line">renderer.renderToString(app, <span class="function"><span class="keyword">function</span> (<span class="params">error, html</span>) </span>&#123;</div><div class="line">  <span class="keyword">if</span> (error) <span class="keyword">throw</span> error</div><div class="line">  <span class="built_in">console</span>.log(html)</div><div class="line">  <span class="comment">// =&gt; &lt;p server-rendered="true"&gt;hello world&lt;/p&gt;</span></div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>Not so scary, right? Of course, this example is much simpler than most applications. We don’t yet have to worry about:</p>
<ul>
<li>A Web Server</li>
<li>Response Streaming</li>
<li>Component Caching</li>
<li>A Build Process</li>
<li>Routing</li>
<li>Vuex State Hydration</li>
</ul>
<p>In the rest of this guide, we’ll walk through how to work with some of these features. Once you understand the basics, we’ll then direct you to more detailed documentation and advanced examples to help you handle edge cases.</p>
<h2 id="Simple-SSR-with-the-Express-Web-Server"><a href="#Simple-SSR-with-the-Express-Web-Server" class="headerlink" title="Simple SSR with the Express Web Server"></a>Simple SSR with the Express Web Server</h2><p>It’s kind of a stretch to call it “server-side rendering” when we don’t actually have a web server, so let’s fix that. We’ll build a very simple SSR app, using only ES5 and without any build step or Vue plugins.</p>
<p>We’ll start off with an app that just tells the user how many seconds they’ve been on the page:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="keyword">new</span> Vue(&#123;</div><div class="line">  template: <span class="string">'&lt;div&gt;You have been here for &#123;&#123; counter &#125;&#125; seconds.&lt;/div&gt;'</span>,</div><div class="line">  data: &#123;</div><div class="line">    counter: <span class="number">0</span></div><div class="line">  &#125;,</div><div class="line">  created: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="keyword">var</span> vm = <span class="keyword">this</span></div><div class="line">    setInterval(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">      vm.counter += <span class="number">1</span></div><div class="line">    &#125;, <span class="number">1000</span>)</div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>To adapt this for SSR, there are a few modifications we’ll have to make, so that it will work both in the browser and within node:</p>
<ul>
<li>When in the browser, add an instance of our app to the global context (i.e. <code>window</code>), so that we can mount it.</li>
<li>When in node, export a factory function so that we can create a fresh instance of the app for every request.</li>
</ul>
<p>Accomplishing this requires a little boilerplate:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="comment">// assets/app.js</span></div><div class="line">(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123; <span class="string">'use strict'</span></div><div class="line">  <span class="keyword">var</span> createApp = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="comment">// ---------------------</span></div><div class="line">    <span class="comment">// BEGIN NORMAL APP CODE</span></div><div class="line">    <span class="comment">// ---------------------</span></div><div class="line"></div><div class="line">    <span class="comment">// Main Vue instance must be returned and have a root</span></div><div class="line">    <span class="comment">// node with the id "app", so that the client-side</span></div><div class="line">    <span class="comment">// version can take over once it loads.</span></div><div class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Vue(&#123;</div><div class="line">      template: <span class="string">'&lt;div id="app"&gt;You have been here for &#123;&#123; counter &#125;&#125; seconds.&lt;/div&gt;'</span>,</div><div class="line">      data: &#123;</div><div class="line">        counter: <span class="number">0</span></div><div class="line">      &#125;,</div><div class="line">      created: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">        <span class="keyword">var</span> vm = <span class="keyword">this</span></div><div class="line">        setInterval(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">          vm.counter += <span class="number">1</span></div><div class="line">        &#125;, <span class="number">1000</span>)</div><div class="line">      &#125;</div><div class="line">    &#125;)</div><div class="line"></div><div class="line">    <span class="comment">// -------------------</span></div><div class="line">    <span class="comment">// END NORMAL APP CODE</span></div><div class="line">    <span class="comment">// -------------------</span></div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="built_in">module</span> !== <span class="string">'undefined'</span> &amp;&amp; <span class="built_in">module</span>.exports) &#123;</div><div class="line">    <span class="built_in">module</span>.exports = createApp</div><div class="line">  &#125; <span class="keyword">else</span> &#123;</div><div class="line">    <span class="keyword">this</span>.app = createApp()</div><div class="line">  &#125;</div><div class="line">&#125;).call(<span class="keyword">this</span>)</div></pre></td></tr></table></figure>
<p>Now that we have our application code, let’s put together an <code>index.html</code> file:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="comment">&lt;!-- index.html --&gt;</span></div><div class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">title</span>&gt;</span>My Vue App<span class="tag">&lt;/<span class="name">title</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"/assets/vue.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"/assets/app.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript">app.$mount(<span class="string">'#app'</span>)</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></div></pre></td></tr></table></figure>
<p>As long as the referenced <code>assets</code> directory contains the <code>app.js</code> file we created earlier, as well as a <code>vue.js</code> file with Vue, we should now have a working single-page application!</p>
<p>Then to get it working with server-side rendering, there’s just one more step - the web server:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="comment">// server.js</span></div><div class="line"><span class="meta">'use strict'</span></div><div class="line"></div><div class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</div><div class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>)</div><div class="line"></div><div class="line"><span class="comment">// Define global Vue for server-side app.js</span></div><div class="line">global.Vue = <span class="built_in">require</span>(<span class="string">'vue'</span>)</div><div class="line"></div><div class="line"><span class="comment">// Get the HTML layout</span></div><div class="line"><span class="keyword">var</span> layout = fs.readFileSync(<span class="string">'./index.html'</span>, <span class="string">'utf8'</span>)</div><div class="line"></div><div class="line"><span class="comment">// Create a renderer</span></div><div class="line"><span class="keyword">var</span> renderer = <span class="built_in">require</span>(<span class="string">'vue-server-renderer'</span>).createRenderer()</div><div class="line"></div><div class="line"><span class="comment">// Create an express server</span></div><div class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>)</div><div class="line"><span class="keyword">var</span> server = express()</div><div class="line"></div><div class="line"><span class="comment">// Serve files from the assets directory</span></div><div class="line">server.use(<span class="string">'/assets'</span>, express.static(</div><div class="line">  path.resolve(__dirname, <span class="string">'assets'</span>)</div><div class="line">))</div><div class="line"></div><div class="line"><span class="comment">// Handle all GET requests</span></div><div class="line">server.get(<span class="string">'*'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">request, response</span>) </span>&#123;</div><div class="line">  <span class="comment">// Render our Vue app to a string</span></div><div class="line">  renderer.renderToString(</div><div class="line">    <span class="comment">// Create an app instance</span></div><div class="line">    <span class="built_in">require</span>(<span class="string">'./assets/app'</span>)(),</div><div class="line">    <span class="comment">// Handle the rendered result</span></div><div class="line">    <span class="function"><span class="keyword">function</span> (<span class="params">error, html</span>) </span>&#123;</div><div class="line">      <span class="comment">// If an error occurred while rendering...</span></div><div class="line">      <span class="keyword">if</span> (error) &#123;</div><div class="line">        <span class="comment">// Log the error in the console</span></div><div class="line">        <span class="built_in">console</span>.error(error)</div><div class="line">        <span class="comment">// Tell the client something went wrong</span></div><div class="line">        <span class="keyword">return</span> response</div><div class="line">          .status(<span class="number">500</span>)</div><div class="line">          .send(<span class="string">'Server Error'</span>)</div><div class="line">      &#125;</div><div class="line">      <span class="comment">// Send the layout with the rendered app's HTML</span></div><div class="line">      response.send(layout.replace(<span class="string">'&lt;div id="app"&gt;&lt;/div&gt;'</span>, html))</div><div class="line">    &#125;</div><div class="line">  )</div><div class="line">&#125;)</div><div class="line"></div><div class="line"><span class="comment">// Listen on port 5000</span></div><div class="line">server.listen(<span class="number">5000</span>, <span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</div><div class="line">  <span class="keyword">if</span> (error) <span class="keyword">throw</span> error</div><div class="line">  <span class="built_in">console</span>.log(<span class="string">'Server is running at localhost:5000'</span>)</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>And that’s it! Here’s <a href="https://github.com/chrisvfritz/vue-ssr-demo-simple" target="_blank" rel="external">the full application</a>, in case you’d like to clone it and experiment further. Once you have it running locally, you can confirm that server-side rendering really is working by right-clickig on the page and selecting <code>View Page Source</code> (or similar). You should see this in the body:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span> <span class="attr">server-rendered</span>=<span class="string">"true"</span>&gt;</span>You have been here for 0 seconds&amp;period;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></div></pre></td></tr></table></figure>
<p>instead of:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div></pre></td></tr></table></figure>
<h2 id="Response-Streaming"><a href="#Response-Streaming" class="headerlink" title="Response Streaming"></a>Response Streaming</h2><p>Vue also supports rendering to a <strong>stream</strong>, which is preferred for web servers that support streaming. This allows HTML to be written to the response <em>as it’s generated</em>, rather than all at once at the end. The result is requests are served faster, with no downsides!</p>
<p>To adapt our app from the previous section for streaming, we can simply replace the <code>server.get(&#39;*&#39;, ...)</code> block with the following:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="comment">// Split the layout into two sections of HTML</span></div><div class="line"><span class="keyword">var</span> layoutSections = layout.split(<span class="string">'&lt;div id="app"&gt;&lt;/div&gt;'</span>)</div><div class="line"><span class="keyword">var</span> preAppHTML = layoutSections[<span class="number">0</span>]</div><div class="line"><span class="keyword">var</span> postAppHTML = layoutSections[<span class="number">1</span>]</div><div class="line"></div><div class="line"><span class="comment">// Handle all GET requests</span></div><div class="line">server.get(<span class="string">'*'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">request, response</span>) </span>&#123;</div><div class="line">  <span class="comment">// Render our Vue app to a stream</span></div><div class="line">  <span class="keyword">var</span> stream = renderer.renderToStream(<span class="built_in">require</span>(<span class="string">'./assets/app'</span>)())</div><div class="line"></div><div class="line">  <span class="comment">// Write the pre-app HTML to the response</span></div><div class="line">  response.write(preAppHTML)</div><div class="line"></div><div class="line">  <span class="comment">// Whenever new chunks are rendered...</span></div><div class="line">  stream.on(<span class="string">'data'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">chunk</span>) </span>&#123;</div><div class="line">    <span class="comment">// Write the chunk to the response</span></div><div class="line">    response.write(chunk)</div><div class="line">  &#125;)</div><div class="line"></div><div class="line">  <span class="comment">// When all chunks are rendered...</span></div><div class="line">  stream.on(<span class="string">'end'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="comment">// Write the post-app HTML to the response</span></div><div class="line">    response.end(postAppHTML)</div><div class="line">  &#125;)</div><div class="line"></div><div class="line">  <span class="comment">// If an error occurs while rendering...</span></div><div class="line">  stream.on(<span class="string">'error'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</div><div class="line">    <span class="comment">// Log the error in the console</span></div><div class="line">    <span class="built_in">console</span>.error(error)</div><div class="line">    <span class="comment">// Tell the client something went wrong</span></div><div class="line">    <span class="keyword">return</span> response</div><div class="line">      .status(<span class="number">500</span>)</div><div class="line">      .send(<span class="string">'Server Error'</span>)</div><div class="line">  &#125;)</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>As you can see, it’s not much more complicated than the previous version, even if streams may be conceptually new to you. We just:</p>
<ol>
<li>Set up the stream</li>
<li>Write the HTML that comes before the app to the response</li>
<li>Write the app HTML to the response as it becomes available</li>
<li>Write the HTML that comes after the app to the response and end it</li>
<li>Handle any errors</li>
</ol>
<h2 id="Component-Caching"><a href="#Component-Caching" class="headerlink" title="Component Caching"></a>Component Caching</h2><p>Vue’s SSR is very fast by default, but you can further improve performance by caching rendered components. This should be considered an advanced feature however, as caching the wrong components (or the right components with the wrong key) could lead to misrendering your app. Specifically:</p>
<p class="tip">You should not cache a component containing child components that rely on global state (e.g. from a vuex store). If you do, those child components (and in fact, the entire sub-tree) will be cached as well. Be especially wary with components that accept slots/children.</p>

<h3 id="Setup"><a href="#Setup" class="headerlink" title="Setup"></a>Setup</h3><p>With that warning out of the way, here’s how you cache components.</p>
<p>First, you’ll need to provide your renderer with a <a href="https://www.npmjs.com/package/vue-server-renderer#cache" target="_blank" rel="external">cache object</a>. Here’s a simple example using <a href="https://github.com/isaacs/node-lru-cache" target="_blank" rel="external">lru-cache</a>:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="keyword">var</span> createRenderer = <span class="built_in">require</span>(<span class="string">'vue-server-renderer'</span>).createRenderer</div><div class="line"><span class="keyword">var</span> lru = <span class="built_in">require</span>(<span class="string">'lru-cache'</span>)</div><div class="line"></div><div class="line"><span class="keyword">var</span> renderer = createRenderer(&#123;</div><div class="line">  cache: lru(<span class="number">1000</span>)</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>That will cache up to 1000 unique renders. For other configurations that more closely align to memory usage, see <a href="https://github.com/isaacs/node-lru-cache#options" target="_blank" rel="external">the lru-cache options</a>.</p>
<p>Then for components you want to cache, you must provide them with:</p>
<ul>
<li>a unique <code>name</code></li>
<li>a <code>serverCacheKey</code> function, returning a unique key scoped to the component</li>
</ul>
<p>For example:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">Vue.component(&#123;</div><div class="line">  name: <span class="string">'list-item'</span>,</div><div class="line">  template: <span class="string">'&lt;li&gt;&#123;&#123; item.name &#125;&#125;&lt;/li&gt;'</span>,</div><div class="line">  props: [<span class="string">'item'</span>],</div><div class="line">  serverCacheKey: <span class="function"><span class="keyword">function</span> (<span class="params">props</span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> props.item.type + <span class="string">'::'</span> + props.item.id</div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<h3 id="Ideal-Components-for-Caching"><a href="#Ideal-Components-for-Caching" class="headerlink" title="Ideal Components for Caching"></a>Ideal Components for Caching</h3><p>Any “pure” component can be safely cached - that is, any component that is guaranteed to generate the same HTML given the same props. Common examples of these include:</p>
<ul>
<li>Static components (i.e. they always generate the same HTML, so the <code>serverCacheKey</code> function can just return <code>true</code>)</li>
<li>List item components (when part of large lists, caching these can significantly improve performance)</li>
<li>Generic UI components (e.g. buttons, alerts, etc - at least those that accept content through props rather than slots/children)</li>
</ul>
<h2 id="Build-Process-Routing-and-Vuex-State-Hydration"><a href="#Build-Process-Routing-and-Vuex-State-Hydration" class="headerlink" title="Build Process, Routing, and Vuex State Hydration"></a>Build Process, Routing, and Vuex State Hydration</h2><p>By now, you should understand the fundamental concepts behind server-side rendering. However, as you introduce a build process, routing, and vuex, each introduces its own considerations.</p>
<p>To truly master server-side rendering in complex applications, we recommend a deep dive into the following resources:</p>
<ul>
<li><a href="https://www.npmjs.com/package/vue-server-renderer#api" target="_blank" rel="external">vue-server-renderer docs</a>: more details on topics covered here, as well as documentation of more advanced topics, such as <a href="https://www.npmjs.com/package/vue-server-renderer#why-use-bundlerenderer" target="_blank" rel="external">preventing cross-request contamination</a> and <a href="https://www.npmjs.com/package/vue-server-renderer#creating-the-server-bundle" target="_blank" rel="external">adding a separate server build</a></li>
<li><a href="https://github.com/vuejs/vue-hackernews-2.0" target="_blank" rel="external">vue-hackernews-2.0</a>: the definitive example of integrating all major Vue libraries and concepts in a single application</li>
</ul>

    
      <div class="guide-links">
        
          <span>← <a href="/guide/unit-testing.html">Unit Testing</a></span>
        
        
          <span style="float:right"><a href="/guide/migration.html">Migration from 1.x</a> →</span>
        
      </div>
    
    <div class="footer">
      Caught a mistake or want to contribute to the documentation?
      <a href="https://github.com/vuejs/vuejs.org/blob/master/src/guide/ssr.md" target="_blank">
        Edit this page on Github!
      </a>
    </div>
</div>

                
            </div>
            <script src="//cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
            <script src="/js/smooth-scroll.min.js"></script>
            <script src="/js/common.js"></script>
        

        <script src="//cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script><script src="https://cdn.jsdelivr.net/gh/shentao/vuejs-outdated-docs-modal@v1.3/prompt.min.js"></script>
        <script>
            document.addEventListener('DOMContentLoaded', function() {
                FastClick.attach(document.body);
            }, false);
        </script>
    </body>
</html>
